package hu.arguscab.ai.game;

import hu.arguscab.ai.DecisionTree;
import hu.arguscab.ai.Fitnessor;
import hu.arguscab.ai.Path;
import hu.arguscab.game.CompoundAction;
import hu.arguscab.game.Controller;
import hu.arguscab.game.GameAction;
import hu.arguscab.game.GameCompoundAction;
import hu.arguscab.game.GameScene;
import hu.arguscab.game.Ship;
import hu.arguscab.physic.Vector;

import org.springframework.beans.factory.annotation.Required;

/**
 *
 * @author sharp
 */
public class Bot extends Controller{

	private static final CompoundAction NOTHING_ACTION;

	protected int decisionTick;		// hány ticket számol előre az AI

	private DecisionTree decisionTree;
	private Path<CompoundAction> localPath;
	private int tick = 0;
	private CompoundAction current;
	private boolean reached;
	private Fitnessor[] fitnessors;
	private Ship target;
	private VisualDecisionTree visualTree = null;
	private boolean drawVisualTree;
	
	// A* stuff
	private Ship localTarget = new Ship(null, null);
	private Path<Vector> path;

	static {
		NOTHING_ACTION = new GameCompoundAction();
		NOTHING_ACTION.addAction(GameAction.NOTHING);
	}

	public Bot() {
		localPath = new Path<CompoundAction>();
		path = new Path<Vector>();
	}

	public CompoundAction control() {
		if (target == null)
			return NOTHING_ACTION;
		
		if ( isReachedDestination() == true ) {
			clearDecisions();
			if ( path.isEmpty() == false ) {
				localTarget.getState().setPos(path.poll());
			} else
				doCommand(Command.STOP);
		}
			/*// Ha eddig a célpont közelében volt, de kisodrodott, akkor uj terv kell
			if ( reached ) {
				clearDecisions();
				doCommand(Command.TARGET);
				reached = false;
			}
		}
		else {
			if ( reached == false ) {
				clearDecisions();
				doCommand(Command.STOP);
				reached = true;
			}
		}*/
		if ( tick == 0 ) {
			if ( localPath.isEmpty()) {
				decisionTree.clear();
				localPath = decisionTree.makeDecision();
			}
			current = localPath.poll();
			tick = decisionTick;
		}
		--tick;
		return current;
	}

	public int getDecisionTick() {
		return decisionTick;
	}

	public void setDecisionTick(int thinkTick) {
		this.decisionTick = thinkTick;
		decisionTree.getCreator().setDepth(decisionTick);
	}

	private void clearDecisions() {
		tick = 0;
		localPath.clear();
		path.clear();
	}
	private boolean isReachedDestination() {
		return localTarget == null ||
				localTarget.getState().getPos()
				.getDistanceFrom(getMyShip().getState().getPos()) < 30;
	}

	@Required
	public void setDecesionTree(DecisionTree decesionTree) {
		this.decisionTree = decesionTree;
	}

	public void init() {
		setDecisionTick(decisionTick);
		
		doCommand(Command.TARGET);
	}

	@Override
	public void setMyShip(Ship myShip) {
		super.setMyShip(myShip);
		((GameNodeCreator)decisionTree.getCreator()).setShip(getMyShip());
	}

	public void doCommand(Command c) {
		assert fitnessors.length > c.ordinal() : "Nem lett minden Commandhoz Fitnessor definiálva!";
		assert fitnessors[c.ordinal()] != null : "Nem lett minden Commandhoz Fitnessor definiálva!";
		decisionTree.setFitnessor( fitnessors[c.ordinal()] );
	}

	public void setFitnessors(Fitnessor[] fitnessors) {
		this.fitnessors = fitnessors;
	}

	public Ship getTarget() {
		return localTarget;
	}

	public void setTarget(Ship target) {
		clearDecisions();
		this.target = target;
		path = GameScene.map.getPath(getMyShip().getState().getPos(), target.getState().getPos());
	}

	public DecisionTree getDecisionTree() {
		return decisionTree;
	}

	public Fitnessor getFitnessors(Command cmd) {
		assert fitnessors.length > cmd.ordinal() : "Nem lett minden Commandhoz Fitnessor definiálva!";
		assert fitnessors[cmd.ordinal()] != null : "Nem lett minden Commandhoz Fitnessor definiálva!";
		return fitnessors[cmd.ordinal()];
	}

	public void setDecisionDepth(int d) {
		decisionTree.getTerminator().setMaxDepth(d);
	}


	synchronized public boolean isDrawVisualTree() {
		return drawVisualTree;
	}

	synchronized public void setDrawVisualTree(boolean drawVisualTree) {
		this.drawVisualTree = drawVisualTree;
		if ( drawVisualTree ) {
			if ( visualTree == null )
				visualTree = new VisualDecisionTree();
			visualTree.setShip(getMyShip());
		}
	}

	synchronized public void draw() {
		if ( drawVisualTree )
			visualTree.draw();
	}
}
